package com.zdya.combatdocuments.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdya.combatdocuments.constant.Constants;
import com.zdya.combatdocuments.entity.Document;
import com.zdya.combatdocuments.entity.vo.DocumentVO;
import com.zdya.combatdocuments.entity.vo.PageQuery;
import com.zdya.combatdocuments.exception.BusinessException;
import com.zdya.combatdocuments.mapper.DocumentMapper;
import com.zdya.combatdocuments.p2pNetwork.NodeUtil;
import com.zdya.combatdocuments.service.DocumentService;
import com.zdya.combatdocuments.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * * @author: bj
 * * @date: 2023/6/2
 * * @desc: 作战文书库实现类
 */
@Slf4j
@Service
public class DocumentServiceImpl extends ServiceImpl<DocumentMapper, Document> implements DocumentService {

    @Value("${server.port}")
    private String port;
    @Autowired
    private DocumentMapper documentMapper;
    @Autowired
    private NodeUtil nodeUtil;

    /**
     * @desc 查询文书列表
     * @param documentVO
     * @return 文书列表
     */
    @Override
    public Page<Document> queryDocs(DocumentVO documentVO, PageQuery pageQuery) {
        // 开启分页
        Page<Document> page = new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize());

        LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<Document>();
        // 文书编号
        wrapper.eq(StrUtil.isNotBlank(documentVO.getSerialNum()), Document::getSerialNum, documentVO.getSerialNum());
        // 文书名称
        wrapper.like(StrUtil.isNotBlank(documentVO.getName()), Document::getName, documentVO.getName());
        // 文书类别
        wrapper.eq(documentVO.getType() != null, Document::getType, documentVO.getType());
        // 文书等级
        wrapper.eq(StrUtil.isNotBlank(documentVO.getDocGrade()), Document::getDocGrade, documentVO.getDocGrade());
        // 发送方要素
        wrapper.eq(StrUtil.isNotBlank(documentVO.getFromElement()), Document::getFromElement, documentVO.getFromElement());
        // 接收方要素
        wrapper.eq(StrUtil.isNotBlank(documentVO.getToElement()), Document::getToElement, documentVO.getToElement());
        // 文书等级
        wrapper.eq(StrUtil.isNotBlank(documentVO.getDocGrade()), Document::getDocGrade, documentVO.getDocGrade());
        // 发送方席位
        wrapper.eq(StrUtil.isNotBlank(documentVO.getFromSeat()), Document::getFromSeat, documentVO.getFromSeat());
        // 接收方席位
        wrapper.eq(StrUtil.isNotBlank(documentVO.getToSeat()), Document::getToSeat, documentVO.getToSeat());
        // 时间查询
        wrapper.between(documentVO.getStartDate() != null && documentVO.getEndDate() != null,
                Document::getCreateDate, documentVO.getStartDate(), documentVO.getEndDate());
        //根据网络id显示相关文书信息
        wrapper.eq(Document::getNetId,nodeUtil.getNetworkId());
        try {
            documentMapper.selectPage(page, wrapper);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return documentMapper.selectPage(page, wrapper);
    }

    /**
     * @desc 导出文书压缩包到指定路径
     * @param ids 主键id数组
     * @return
     */
    @Override
    public void exportDocsByIds(Long[] ids, HttpServletResponse response) throws IOException {
        List<Document> documents = null;
        if (ids.length > 0) {// 批量导出
            List<Long> longs = Arrays.asList(ids);
            documents = documentMapper.selectBatchIds(longs);
        } else {// 全部导出
            // 查询id大于等于0的全部数据
            QueryWrapper<Document> wrapper = new QueryWrapper<Document>();
            wrapper.ge("id", 0);
            documents = documentMapper.selectList(wrapper);
        }
        String zipName = DateUtil.getSdfTimes() + ".zip";
        zipFiles(documents, zipName, response);
    }

    /**
     * @desc 查询预览文件路径
     * @param id 预览文件id
     * @return
     */
    @Override
    public Map<String, String> previewDoc(Long id) {
        Map<String, String> map = new HashMap();
        Document document = documentMapper.selectById(id);
        if (ObjectUtils.isEmpty(document)) {
            throw new BusinessException("暂未查不到相关文件！");
        }
        if (StrUtil.isBlank(document.getPath())) {
            throw new BusinessException("暂未查不到相关文件！");
        }
        String path = document.getPath();
        String localAddr = this.getIpAddr();
        String serverPort = port;
        String filePath = Constants.HTTP + localAddr + ":" + serverPort + path;
        map.put("filePath", filePath);
        return map;
    }

    /**
     * @desc 把要导出的文书压缩为zip文件
     * @param documents
     */
    private void zipFiles(List<Document> documents, String zipName, HttpServletResponse response) throws IOException {
        List<String> fileList = new ArrayList<>();
        for (Document document:documents) {
            fileList.add(document.getPath());
        }
        byte[] buf = new byte[1024];
        BufferedOutputStream bos = null;
        ZipOutputStream out = null;
        try {
            bos = new BufferedOutputStream(response.getOutputStream());
            //响应到浏览器
            response.reset();
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-disposition","attachment;filename=" + zipName);
            out = new ZipOutputStream(bos);
            for (String filePathName:fileList){
                File file = new File(filePathName);
                FileInputStream in = new FileInputStream(file);
                out.putNextEntry(new ZipEntry(file.getName()));
                int len = -1;
                while ((len=in.read(buf))!=-1){
                    out.write(buf,0,len);
                }
                in.close();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (out!=null)
                out.close();
            if (bos!=null)
                bos.close();
        }
    }

    /**
     * @desc 判断当前平台式Linux和windows
     * @return
     */
    private boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
            isWindowsOS = true;
        }
        return isWindowsOS;
    }

    /**
     * @desc 获取ip和端口号
     * @return
     */
    private String getIpAddr() {
        String ip = null;
        // 获取windows下ip和端口号
        if (this.isWindowsOS()) {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
                return ip;
            } catch (Exception e) {
                log.info(e.getMessage(), e);
                e.printStackTrace();
            }
        } else {
            try {
                for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
                    NetworkInterface intf = en.nextElement();
                    String name = intf.getName();
                    if (!name.contains("docker") && !name.contains("lo")) {
                        for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
                            InetAddress inetAddress = enumIpAddr.nextElement();
                            if (!inetAddress.isLoopbackAddress()) {
                                String ipaddress = inetAddress.getHostAddress().toString();
                                if (!ipaddress.contains("::") && !ipaddress.contains("0:0:") && !ipaddress.contains("fe80")) {
                                    ip = ipaddress;
                                    System.out.println(ipaddress);
                                }
                            }
                        }
                    }
                }
            } catch (SocketException e) {
                log.error("getLinuxLocalIp error--->{}", e.getMessage());
                e.printStackTrace();
            }
            log.error("getLinuxLocalIp ip--->{}", ip);
            return ip;
        }
        return null;
    }
}
